from jili.core.printlog import print
import rqdatac
from rqdatac import LiveMarketDataClient
from jili.tool.convert import str2datetime
import datetime
from jili.data.db import tradecal
import pandas as pd

"""
SHFE:上海期货交易所
DCE:大连商品交易所
CZCE:郑州商品交易所
CFFEX:中国金融交易所
INE:上海能源中心(原油在这里)
KQ:快期 (所有主连合约, 指数都归属在这里)
KQD:快期外盘主连合约
SSWE:上期所仓单
SSE:上海证券交易所
SZSE:深圳证券交易所
GFEX:广州期货交易所
"""
ats2rq_mkcode={
    "SH":"SSE",
    "SZ":"SZSE",
    # "BJ":"BJSE",
    # "HK":"HK",
    # "SHK":"SHK",
    # "ZHK":"ZHK",
    'CFFEX':"CFFEX",
    'CZCE':"CZCE",
    'DCE':"DCE",
    'GFEX':"GFEX",
    'INE':"INE",
    'SHFE' :"SHFE",
    "KQ":"KQ",
    "KQD":"KQD"
}
rq2ats_mkcode={v: k for k, v in ats2rq_mkcode.items()}
class tick_l1():
    def __init__(self):
        self.ticks={}
    def reset(self):
        self.ticks={}
    def dftick2tick0(self,k):
        if isinstance(k, pd.DataFrame):
            if not k.empty:
                k = k.to_dict(orient="records")
                kk={}
                # prei=k[0]
                predate=k[0]["datetime"][:10]
                ticks=[]
                for i in k:
                    date=i["datetime"][:10]
                    i["timekey"] = str2datetime(i["datetime"].split(".")[0])
                    if predate!=date:
                        date0=str2datetime(predate)
                        kk[date0]=ticks
                        self.reset()
                        ticks=[]
                        predate=date
                    t=self.xtick2tick1(i["code"], i)
                    if t is None:
                        continue
                    ticks.append(t)
                if ticks:
                    date0 = str2datetime(date)
                    kk[date0] = ticks
                    # prei=i
                return kk
            else:
                return []
        else:
            return []

    def xtick2tick1(self,code,tick,call=None):
        timekey=tick["timekey"]
        cum_amount = tick["amount"]
        cum_volume = tick["volume"]
        r=self.ticks.get(code)
        if r is None:
            self.ticks[code] = (timekey, cum_amount, cum_volume)
            amount = cum_amount
            volume = cum_volume
        else:
            timekey0, cum_amount0, cum_volume0 = r
            if timekey0 < timekey:
                amount =  cum_amount-cum_amount0
                volume =  cum_volume-cum_volume0
                self.ticks[code] = (timekey, cum_amount, cum_volume)
            else:
                return None
        t = {}
        t["timekey"] = timekey
        t["obj"], t["mkcode"] = code2obj(code)
        t["code"] = t["obj"]+"."+ t["mkcode"]
        t["lastPrice"] = tick["last_price"]
        t["amount"] = amount
        t["volume"] = volume
        t["cumAmount"] = cum_amount
        t["cumVolume"] = cum_volume
        t["askPrice"] = [tick["ask_price1"],tick["ask_price2"],tick["ask_price3"],tick["ask_price4"],tick["ask_price5"]]
        t["bidPrice"] = [tick["bid_price1"],tick["bid_price2"],tick["bid_price3"],tick["bid_price4"],tick["bid_price5"]]
        t["askVol"] = [tick["ask_volume1"],tick["ask_volume2"],tick["ask_volume3"],tick["ask_volume4"],tick["ask_volume5"]]
        t["bidVol"] = [tick["bid_volume1"],tick["bid_volume2"],tick["bid_volume3"],tick["bid_volume4"],tick["bid_volume5"]]
        t["high"] = tick["highest"]
        t["low"] = tick["lowest"]
        if call is not None:
            call(t)
        return t
class tick_l1_future():
    def __init__(self,pos=0):
        self.ticks={}
        self.prepos=pos
    def reset(self):
        self.ticks={}
    def get_timekey(self,tt):
        tstr = tt["datetime"]
        obj,mkcode=tt["code"].split(".")
        if mkcode == "CZCE":
            f = tstr.split(".")[-1].replace("0", "")
            if f == "1":
                f = "500"
            elif f == "2":
                f = "600"
            elif f == "3":
                f = "700"
            elif f == "4":
                f = "800"
            elif f == "5":
                f = "900"
        else:
            f = tstr.split(".")[-1][:3]
            f1 = tstr[-4]
            if f1 != '0':
                f = str(int(f) + int(f1) * 100)
        if f != "":
            tstr = tstr.split(".")[0] + "." + f + "00"
        else:
            tstr = tstr.split(".")[0] + ".000"
        timekey = datetime.datetime.strptime(tstr, '%Y-%m-%d %H:%M:%S.%f')
        return timekey
    def dftick2tick0(self,k):
        if isinstance(k, pd.DataFrame):
            if not k.empty:
                k = k.to_dict(orient="records")
                kk={}
                tk=self.get_timekey(k[0])
                predate=tradecal.gettradeday_bytimekey(tk)
                ticks=[]
                for i in k:
                    tk=self.get_timekey(i)
                    date=tradecal.gettradeday_bytimekey(tk)
                    i["timekey"] = tk
                    if predate!=predate:
                        # date0=str2datetime(date)
                        kk[predate]=ticks
                        self.reset()
                        ticks=[]
                        predate=date
                    t=self.xtick2tick1(i["code"], i)
                    if t is not None:
                        ticks.append(t)
                if ticks:
                    kk[date] = ticks
                return kk
            else:
                return []
        else:
            return []

    def xtick2tick1(self,code,tick,call=None):
        timekey=tick["timekey"]
        cum_amount = tick["amount"]
        cum_volume = tick["volume"]
        cum_pos=tick["open_interest"]
        r=self.ticks.get(code)
        if r is None:
            self.ticks[code] = (timekey, cum_amount, cum_volume)
            amount = cum_amount
            volume = cum_volume
        else:
            timekey0, cum_amount0, cum_volume0 = r
            if timekey0 < timekey:
                amount =  cum_amount-cum_amount0
                volume =  cum_volume-cum_volume0
                self.ticks[code] = (timekey, cum_amount, cum_volume)
            else:
                return None
        t = {}
        t["timekey"] = timekey
        t["obj"], t["mkcode"] = code.split(".")
        # t["code"] = t["obj"]+"."+ t["mkcode"]
        t["code"]=code
        t["lastPrice"] = tick["last_price"]
        t["amount"] = amount
        t["volume"] = volume
        t["pos"]=cum_pos-self.prepos
        t["cumAmount"] = cum_amount
        t["cumVolume"] = cum_volume
        t["cumPos"]=cum_pos
        t["askPrice"] = [tick["ask_price1"]]#,tick["ask_price2"],tick["ask_price3"],tick["ask_price4"],tick["ask_price5"]]
        t["bidPrice"] = [tick["bid_price1"]]#,tick["bid_price2"],tick["bid_price3"],tick["bid_price4"],tick["bid_price5"]]
        t["askVol"] = [tick["ask_volume1"]]#,tick["ask_volume2"],tick["ask_volume3"],tick["ask_volume4"],tick["ask_volume5"]]
        t["bidVol"] = [tick["bid_volume1"]]#,tick["bid_volume2"],tick["bid_volume3"],tick["bid_volume4"],tick["bid_volume5"]]
        t["high"] = tick["highest"]
        t["low"] = tick["lowest"]
        self.prepos=cum_pos
        if call is not None:
            call(t)
        return t

def obj2code(obj,mkcode=None):
    if not obj[0].isalpha():
        if mkcode is None:
            if "." in obj:
                obj,mkcode=obj.split(".")
                if mkcode in ats2rq_mkcode.keys():
                    mkcode=ats2rq_mkcode[mkcode]
            else:
                if obj[0]>"3":
                    mkcode="SSE"
                else:
                    mkcode="SZSE"
        else:
            if mkcode in ats2rq_mkcode.keys():
                mkcode = ats2rq_mkcode[mkcode]
        return mkcode+"."+obj
    else:
        if "." in obj:
            obj, mkcode = obj.split(".")
            if mkcode in ats2rq_mkcode.keys():
                mkcode = ats2rq_mkcode[mkcode]
            return mkcode + "." + obj
        else:
            return obj
def code2obj(code):
    if "." in code:
        mkcode,obj=code.split(".")
        if mkcode in rq2ats_mkcode.keys():
            mkcode=rq2ats_mkcode[mkcode]
    else:
        mkcode=None
    return obj,mkcode
rq2ats_products={
    "CS":"stock",
    "INDX":"index",
    "ETF":"etf",
    "LOF":"fund",
    "Spot":"spot",
    "Repo":"repo",
    "Convertible":"convertible",
    "Future":"future",
    "Option":"option"
}
ats2rq_mkcode={v: k for k, v in rq2ats_products.items()}
periods={#60s, 300s, 900s, 1800s, 3600s
    "tick": "tick",
    "k1m":"1m",
    "k3m":"3m",
    "k5m":"5m",
    "k10m":"10m",
    "k15m":"15m",
    "k30m":"30m",
    "k60m":"60m",
    "k1d":"1d",
    "k1w":"1w"
}
periods1={v: k for k, v in periods.items()}
ats2rq_fqtype={
    "qfq":"pre",
    "hfq":"post",
    "bfq":"none"
}
def ats2rq_period(period):
    if period in periods.keys():
        return periods[period]
    else:
        return period[1:]
class pricetool():
    def __init__(self):
        self.calls={}
        self.obj_infos = {}
        try:
            # rqdatac.init()
            self.tool= LiveMarketDataClient()
        except Exception as e:
            print(e)
    def run(self):
        self.tool.listen(handler=self.handle_msg)
    def get_objinfo(self,obj):
        if obj not in self.obj_infos.keys():
            code = obj2code(obj)
            self.obj_infos[obj] = rqdatac.instruments(code, market='cn')
        return self.obj_infos[obj]
    def get_tradeday(self,count=1,end_date=None):
        if end_date is None:
            now = datetime.datetime.now()
            today = datetime.datetime(now.year, now.month, now.day)
        else:
            if isinstance(end_date,str):
                today=str2datetime(end_date)
            else:
                today=end_date
        start=today-datetime.timedelta(days=2*count+5)
        tdays=rqdatac.get_trading_dates(start_date=start,end_date=today)
        r=[]
        # count0=count+1
        count0=count
        for i in tdays[-count0:]:
            r.append(datetime.datetime(i.year,i.month,i.day))
        return r
    def istradeday(self):
        now = datetime.datetime.now()
        today = datetime.datetime(now.year, now.month, now.day)
        r=rqdatac.get_trading_dates(start_date=today,end_date=today)
        if len(r)>0:
            return True
        else:
            return False
    def subscribe(self,obj, period='k30m', callback=None):
        if isinstance(obj,str):
            codes=[obj2code(obj)]
        else:
            codes=[]
            for i in obj:
                codes.append(obj2code(i))
        period0=ats2rq_period(period)
        for code in codes:
            if period[0]=="k":
                code0="bar_"
                code1=period0
            else:
                code0="tick_"
                code1=""
            key=code0+code+"_"+code1
            self.tool.subscribe(key)
            if code not in self.calls.keys():
                self.calls[code]= {}
            self.calls[code][period]=callback



    def get_today_bar(self,obj,period="k1d"):
        bars=self.get_prebars(obj,count=1,period=period,fqtype="bfq")
        if bars:
            return bars[-1]
        else:
            return {}
    def get_prebars(self,obj,count=1,period="k1d",fqtype="qfq",start_date='',end_date=''):
        obj=obj2code(obj)
        fqtype0 = ats2rq_fqtype.get(fqtype,"none")

        period0=ats2rq_period(period)
        if end_date == '':
            end_date0 = self.get_tradeday(1)[0]
        else:
            end_date0 = end_date
        if count>0:
            if start_date=='':
                tdays=self.get_tradeday(count=count,end_date=end_date0)
                start_date=tdays[0]
        print("price_rq get_price",obj,start_date,end_date,end_date0,count,period,period0,fqtype,fqtype0)
        bars=rqdatac.get_price(obj, start_date=start_date, end_date=end_date0, frequency=period0, fields=None, adjust_type=fqtype0, skip_suspended =False, market='cn', expect_df=True,time_slice=None)
        if bars is None:
            return []
        if bars.empty:
            return []
        index0 = bars.index.to_list()
        # if isinstance(index0[0], tuple):
        obj = []
        ids = []
        tk = []
        for i in index0:
            obj.append(i[0].split(".")[0])
            ids.append(i[0])
            tk.append(i[1])
        bars["timekey"] = tk
        bars["obj"] = obj
        bars["order_book_id"] = ids
        bars["amount"] = bars["total_turnover"]
        return bars.to_dict("records")

if __name__ == "__main__":
    pt=pricetool()
    b=pt.get_prebars("000400.XSHE",fqtype="qfq",period="k15m",start_date="20250516")
    print("end")